﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using DiscoveryLogic.Common.Utilities;

namespace DiscoveryLogic.Analytics.DataObjects.Filters
{
    public class NetworkExclusionSetting
    {
        #region props
        private string _NetworkName;
        /// <summary></summary>
        public string NetworkName
        {
            get
            {
                return this._NetworkName;
            }
            set
            {
                this._NetworkName = value;
            }
        }

        private List<EntityType> _ExcludeEntityTypes;
        /// <summary></summary>
        public List<EntityType> ExcludeEntityTypes
        {
            get
            {
                return this._ExcludeEntityTypes;
            }
            set
            {
                this._ExcludeEntityTypes = value;
            }
        }

        private List<EntityQuery> _ExcludeQueries;
        /// <summary></summary>
        public List<EntityQuery> ExcludeQueries
        {
            get
            {
                return this._ExcludeQueries;
            }
            set
            {
                this._ExcludeQueries = value;
            }
        }

        private List<EdgeSelection> _ExcludedEdges;
        /// <summary></summary>
        public List<EdgeSelection> ExcludedEdges
        {
            get
            {
                return this._ExcludedEdges;
            }
            set
            {
                this._ExcludedEdges = value;
            }
        }
        #endregion

        public void Save()
        {
            string filePath = Path.Combine(DataFolder.NetworkDataFolder,
                                           this.NetworkName + DataFolder.NetworkExclusionSettingFileExtension);
            if(File.Exists(filePath))
                File.Delete(filePath);
            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml("<NetworkEx></NetworkEx>");
            XmlNode root = xDoc.DocumentElement;
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "NetworkName",this.NetworkName);
            XmlNode exEntityNodes = XmlDataUtil.AddElement(ref xDoc, root, "ExEntities");
            if(this.ExcludeEntityTypes !=null && this.ExcludeEntityTypes.Count>0)
            {
                foreach(EntityType entityType in this.ExcludeEntityTypes)
                {
                    XmlNode exEntityNode = XmlDataUtil.AddElement(ref xDoc, exEntityNodes, "ExEntity");
                    XmlDataUtil.UpdateAttribute(ref xDoc, exEntityNode,"EntityType",entityType.ToString());
                }
            }
            XmlNode exQueryNodes = XmlDataUtil.AddElement(ref xDoc, root, "ExQueries");
            if(this.ExcludeQueries !=null && this.ExcludeQueries.Count>0)
            {
                foreach(EntityQuery query in this.ExcludeQueries)
                {
                    XmlNode exQueryNode = XmlDataUtil.AddElement(ref xDoc, exQueryNodes, "ExQuery");
                    XmlDataUtil.UpdateAttribute(ref xDoc, exQueryNode,"EntityType",query.EntityType.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, exQueryNode, "FieldName", query.FieldName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, exQueryNode, "Op", query.Op.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, exQueryNode, "Against", query.Against);
                }
            }
            XmlNode exEdgeNodes = XmlDataUtil.AddElement(ref xDoc, root, "ExEdges");
            if(this.ExcludedEdges!=null && this.ExcludedEdges.Count>0)
            {
                foreach(EdgeSelection edgeSelect in this.ExcludedEdges)
                {
                    XmlNode exEdgeNode = XmlDataUtil.AddElement(ref xDoc, exEdgeNodes, "ExEdge");
                    XmlDataUtil.UpdateAttribute(ref xDoc, exEdgeNode,"FromEntity",edgeSelect.FromEntity.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, exEdgeNode,"ToEntity",edgeSelect.ToEntity.ToString());
                }
            }

            xDoc.Save(filePath);
        }

        public static NetworkExclusionSetting Default
        {
            get
            {
                NetworkExclusionSetting ex=new NetworkExclusionSetting();
                ex.ExcludedEdges=new List<EdgeSelection>();
                ex.ExcludeEntityTypes=new List<EntityType>();
                ex.ExcludeQueries=new List<EntityQuery>();
                ex.NetworkName = string.Empty;
                return ex;
            }
        }

        public static NetworkExclusionSetting Read(string networkName)
        {
            NetworkExclusionSetting ex=new NetworkExclusionSetting();
            string filePath = Path.Combine(DataFolder.NetworkDataFolder,
                                           networkName + DataFolder.NetworkExclusionSettingFileExtension);
            if (!File.Exists(filePath))
            {
                ex = NetworkExclusionSetting.Default;
                ex.NetworkName = networkName;
                return ex;
            }

            XmlDocument xDoc = new XmlDocument();
            xDoc.Load(filePath);
            XmlNode root = xDoc.DocumentElement;
            ex.NetworkName = XmlDataUtil.GetAttributeValue(root, "NetworkName", "");
            XmlNodeList exEntityNodes = root.SelectNodes("ExEntities/ExEntity");
            ex.ExcludeEntityTypes=new List<EntityType>();
            if(exEntityNodes !=null && exEntityNodes.Count>0)
            {
                foreach(XmlNode exEntityNode in exEntityNodes)
                {
                    EntityType entityType =
                        (EntityType)
                        Enum.Parse(typeof (EntityType),
                                   XmlDataUtil.GetAttributeValue(exEntityNode, "EntityType",
                                                                 EntityType.Grants.ToString()));
                    ex.ExcludeEntityTypes.Add(entityType);
                }
            }
            ex.ExcludeQueries=new List<EntityQuery>();
            XmlNodeList exQueryNodes = root.SelectNodes("ExQueries/ExQuery");
            if(exQueryNodes !=null && exQueryNodes.Count>0)
            {
                foreach(XmlNode exQNode in exQueryNodes)
                {
                    EntityQuery query=new EntityQuery();
                    query.EntityType =
                        (EntityType)
                        Enum.Parse(typeof (EntityType),
                                   XmlDataUtil.GetAttributeValue(exQNode, "EntityType", EntityType.Grants.ToString()));
                    query.FieldName = XmlDataUtil.GetAttributeValue(exQNode, "FieldName", "");
                    query.Op =
                        (SqlOp)
                        Enum.Parse(typeof (SqlOp), XmlDataUtil.GetAttributeValue(exQNode, "Op", SqlOp.Equals.ToString()));
                    query.Against = XmlDataUtil.GetAttributeValue(exQNode, "Against", "");
                    ex.ExcludeQueries.Add(query);
                }
            }
            ex.ExcludedEdges=new List<EdgeSelection>();
            XmlNodeList exEdgeNodes = root.SelectNodes("ExEdges/ExEdge");
            if(exEdgeNodes!=null && exEdgeNodes.Count>0)
            {
                foreach(XmlNode exEN in exEdgeNodes)
                {
                    EntityType fromEntity =
                        (EntityType)
                        Enum.Parse(typeof (EntityType),
                                   XmlDataUtil.GetAttributeValue(exEN, "FromEntity", EntityType.Grants.ToString()));
                    EntityType toEntity =
                        (EntityType)
                        Enum.Parse(typeof(EntityType),
                                   XmlDataUtil.GetAttributeValue(exEN, "ToEntity", EntityType.Grants.ToString()));
                    EdgeSelection edgeSelection = new EdgeSelection(fromEntity, toEntity);
                    ex.ExcludedEdges.Add(edgeSelection);
                }
            }
            return ex;
        }

        public bool IsEnabled
        {
            get
            {
                if(this.ExcludedEdges !=null && this.ExcludedEdges.Count>0)
                    return true;
                if(this.ExcludeEntityTypes !=null && this.ExcludeEntityTypes.Count>0)
                    return true;
                if(this.ExcludeQueries !=null && this.ExcludeQueries.Count>0)
                    return true;
                return false;
            }
        }
    }
}
